{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from fastai.imports import *\n",
    "from fastai.data.all import *\n",
    "from fastai.optimizer import *\n",
    "from fastai.learner import *\n",
    "from fastai.callback.core import *\n",
    "from torch.utils.data import TensorDataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp test_utils"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Synthetic Learner\n",
    "\n",
    "> For quick testing of the training loop and Callbacks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from torch.utils.data import TensorDataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def synth_dbunch(a=2, b=3, bs=16, n_train=10, n_valid=2, cuda=False):\n",
    "    def get_data(n):\n",
    "        x = torch.randn(bs*n, 1)\n",
    "        return TensorDataset(x, a*x + b + 0.1*torch.randn(bs*n, 1))\n",
    "    train_ds = get_data(n_train)\n",
    "    valid_ds = get_data(n_valid)\n",
    "    device = default_device() if cuda else None\n",
    "    train_dl = TfmdDL(train_ds, bs=bs, shuffle=True, num_workers=0)\n",
    "    valid_dl = TfmdDL(valid_ds, bs=bs, num_workers=0)\n",
    "    return DataLoaders(train_dl, valid_dl, device=device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class RegModel(Module):\n",
    "    def __init__(self): self.a,self.b = nn.Parameter(torch.randn(1)),nn.Parameter(torch.randn(1))\n",
    "    def forward(self, x): return x*self.a + self.b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "@delegates(Learner.__init__)\n",
    "def synth_learner(n_trn=10, n_val=2, cuda=False, lr=1e-3, data=None, model=None, **kwargs):\n",
    "    if data is None: data=synth_dbunch(n_train=n_trn,n_valid=n_val, cuda=cuda)\n",
    "    if model is None: model=RegModel()\n",
    "    return Learner(data, model, lr=lr, loss_func=MSELossFlat(),\n",
    "                   opt_func=partial(SGD, mom=0.9), **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class VerboseCallback(Callback):\n",
    "    \"Callback that prints the name of each event called\"\n",
    "    def __call__(self, event_name):\n",
    "        print(event_name)\n",
    "        super().__call__(event_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install Utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_env(name):\n",
    "    \"Return env var value if it's defined and not an empty string, or return Unknown\"\n",
    "    res = os.environ.get(name,'')\n",
    "    return res if len(res) else \"Unknown\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def try_import(module):\n",
    "    \"Try to import `module`. Returns module's object on success, None on failure\"\n",
    "    try: return importlib.import_module(module)\n",
    "    except: return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def nvidia_smi(cmd = \"nvidia-smi\"):\n",
    "    try: res = run(cmd)\n",
    "    except OSError as e: return None\n",
    "    return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "res = nvidia_smi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def nvidia_mem():\n",
    "    try: mem = run(\"nvidia-smi --query-gpu=memory.total --format=csv,nounits,noheader\")\n",
    "    except: return None\n",
    "    return mem.strip().split('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['48600', '7982']"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nvidia_mem()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def show_install(show_nvidia_smi:bool=False):\n",
    "    \"Print user's setup information\"\n",
    "\n",
    "    import fastai, platform, fastprogress\n",
    "\n",
    "    rep = []\n",
    "    opt_mods = []\n",
    "\n",
    "    rep.append([\"=== Software ===\", None])\n",
    "    rep.append([\"python\", platform.python_version()])\n",
    "    rep.append([\"fastai\", fastai.__version__])\n",
    "    rep.append([\"fastprogress\", fastprogress.__version__])\n",
    "    rep.append([\"torch\",  torch.__version__])\n",
    "\n",
    "    # nvidia-smi\n",
    "    smi = nvidia_smi()\n",
    "    if smi:\n",
    "        match = re.findall(r'Driver Version: +(\\d+\\.\\d+)', smi)\n",
    "        if match: rep.append([\"nvidia driver\", match[0]])\n",
    "\n",
    "    available = \"available\" if torch.cuda.is_available() else \"**Not available** \"\n",
    "    rep.append([\"torch cuda\", f\"{torch.version.cuda} / is {available}\"])\n",
    "\n",
    "    # no point reporting on cudnn if cuda is not available, as it\n",
    "    # seems to be enabled at times even on cpu-only setups\n",
    "    if torch.cuda.is_available():\n",
    "        enabled = \"enabled\" if torch.backends.cudnn.enabled else \"**Not enabled** \"\n",
    "        rep.append([\"torch cudnn\", f\"{torch.backends.cudnn.version()} / is {enabled}\"])\n",
    "\n",
    "    rep.append([\"\\n=== Hardware ===\", None])\n",
    "\n",
    "    gpu_total_mem = []\n",
    "    nvidia_gpu_cnt = 0\n",
    "    if smi:\n",
    "        mem = nvidia_mem()\n",
    "        nvidia_gpu_cnt = len(ifnone(mem, []))\n",
    "\n",
    "    if nvidia_gpu_cnt: rep.append([\"nvidia gpus\", nvidia_gpu_cnt])\n",
    "\n",
    "    torch_gpu_cnt = torch.cuda.device_count()\n",
    "    if torch_gpu_cnt:\n",
    "        rep.append([\"torch devices\", torch_gpu_cnt])\n",
    "        # information for each gpu\n",
    "        for i in range(torch_gpu_cnt):\n",
    "            rep.append([f\"  - gpu{i}\", (f\"{gpu_total_mem[i]}MB | \" if gpu_total_mem else \"\") + torch.cuda.get_device_name(i)])\n",
    "    else:\n",
    "        if nvidia_gpu_cnt:\n",
    "            rep.append([f\"Have {nvidia_gpu_cnt} GPU(s), but torch can't use them (check nvidia driver)\", None])\n",
    "        else:\n",
    "            rep.append([f\"No GPUs available\", None])\n",
    "\n",
    "\n",
    "    rep.append([\"\\n=== Environment ===\", None])\n",
    "\n",
    "    rep.append([\"platform\", platform.platform()])\n",
    "\n",
    "    if platform.system() == 'Linux':\n",
    "        distro = try_import('distro')\n",
    "        if distro:\n",
    "            # full distro info\n",
    "            rep.append([\"distro\", ' '.join(distro.linux_distribution())])\n",
    "        else:\n",
    "            opt_mods.append('distro');\n",
    "            # partial distro info\n",
    "            rep.append([\"distro\", platform.uname().version])\n",
    "\n",
    "    rep.append([\"conda env\", get_env('CONDA_DEFAULT_ENV')])\n",
    "    rep.append([\"python\", sys.executable])\n",
    "    rep.append([\"sys.path\", \"\\n\".join(sys.path)])\n",
    "\n",
    "    print(\"\\n\\n```text\")\n",
    "\n",
    "    keylen = max([len(e[0]) for e in rep if e[1] is not None])\n",
    "    for e in rep:\n",
    "        print(f\"{e[0]:{keylen}}\", (f\": {e[1]}\" if e[1] is not None else \"\"))\n",
    "\n",
    "    if smi:\n",
    "        if show_nvidia_smi: print(f\"\\n{smi}\")\n",
    "    else:\n",
    "        if torch_gpu_cnt: print(\"no nvidia-smi is found\")\n",
    "        else: print(\"no supported gpus found on this system\")\n",
    "\n",
    "    print(\"```\\n\")\n",
    "\n",
    "    print(\"Please make sure to include opening/closing ``` when you paste into forums/github to make the reports appear formatted as code sections.\\n\")\n",
    "\n",
    "    if opt_mods:\n",
    "        print(\"Optional package(s) to enhance the diagnostics can be installed with:\")\n",
    "        print(f\"pip install {' '.join(opt_mods)}\")\n",
    "        print(\"Once installed, re-run this utility to get the additional information\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "```text\n",
      "=== Software === \n",
      "python        : 3.8.5\n",
      "fastai        : 2.1.5\n",
      "fastprogress  : 0.2.7\n",
      "torch         : 1.6.0\n",
      "nvidia driver : 450.80\n",
      "torch cuda    : 10.2 / is available\n",
      "torch cudnn   : 7605 / is enabled\n",
      "\n",
      "=== Hardware === \n",
      "nvidia gpus   : 2\n",
      "torch devices : 2\n",
      "  - gpu0      : Quadro RTX 8000\n",
      "  - gpu1      : GeForce RTX 2070 SUPER\n",
      "\n",
      "=== Environment === \n",
      "platform      : Linux-5.4.0-52-generic-x86_64-with-glibc2.10\n",
      "distro        : #57-Ubuntu SMP Thu Oct 15 10:57:00 UTC 2020\n",
      "conda env     : fastai\n",
      "python        : /home/tcapelle/miniconda3/envs/fastai/bin/python\n",
      "sys.path      : /home/tcapelle/Apps/fastai/nbs\n",
      "/home/tcapelle/miniconda3/envs/fastai/lib/python38.zip\n",
      "/home/tcapelle/miniconda3/envs/fastai/lib/python3.8\n",
      "/home/tcapelle/miniconda3/envs/fastai/lib/python3.8/lib-dynload\n",
      "\n",
      "/home/tcapelle/miniconda3/envs/fastai/lib/python3.8/site-packages\n",
      "/home/tcapelle/Apps/nbdev\n",
      "/home/tcapelle/Apps/fastai\n",
      "/home/tcapelle/miniconda3/envs/fastai/lib/python3.8/site-packages/IPython/extensions\n",
      "/home/tcapelle/.ipython\n",
      "\n",
      "Tue Nov 10 10:05:34 2020       \n",
      "+-----------------------------------------------------------------------------+\n",
      "| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |\n",
      "|-------------------------------+----------------------+----------------------+\n",
      "| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |\n",
      "| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |\n",
      "|                               |                      |               MIG M. |\n",
      "|===============================+======================+======================|\n",
      "|   0  Quadro RTX 8000     Off  | 00000000:08:00.0 Off |                  Off |\n",
      "| 33%   42C    P8    26W / 260W |     19MiB / 48600MiB |      0%      Default |\n",
      "|                               |                      |                  N/A |\n",
      "+-------------------------------+----------------------+----------------------+\n",
      "|   1  GeForce RTX 207...  Off  | 00000000:09:00.0 Off |                  N/A |\n",
      "|  0%   43C    P8    29W / 215W |      9MiB /  7982MiB |      0%      Default |\n",
      "|                               |                      |                  N/A |\n",
      "+-------------------------------+----------------------+----------------------+\n",
      "                                                                               \n",
      "+-----------------------------------------------------------------------------+\n",
      "| Processes:                                                                  |\n",
      "|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |\n",
      "|        ID   ID                                                   Usage      |\n",
      "|=============================================================================|\n",
      "|    0   N/A  N/A      1035      G   /usr/lib/xorg/Xorg                 10MiB |\n",
      "|    0   N/A  N/A      1236      G   /usr/bin/gnome-shell                4MiB |\n",
      "|    1   N/A  N/A      1035      G   /usr/lib/xorg/Xorg                  4MiB |\n",
      "+-----------------------------------------------------------------------------+\n",
      "\n",
      "```\n",
      "\n",
      "Please make sure to include opening/closing ``` when you paste into forums/github to make the reports appear formatted as code sections.\n",
      "\n",
      "Optional package(s) to enhance the diagnostics can be installed with:\n",
      "pip install distro\n",
      "Once installed, re-run this utility to get the additional information\n"
     ]
    }
   ],
   "source": [
    "#hide\n",
    "show_install(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## - Export"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Converted 00_torch_core.ipynb.\n",
      "Converted 01_layers.ipynb.\n",
      "Converted 01a_losses.ipynb.\n",
      "Converted 02_data.load.ipynb.\n",
      "Converted 03_data.core.ipynb.\n",
      "Converted 04_data.external.ipynb.\n",
      "Converted 05_data.transforms.ipynb.\n",
      "Converted 06_data.block.ipynb.\n",
      "Converted 07_vision.core.ipynb.\n",
      "Converted 08_vision.data.ipynb.\n",
      "Converted 09_vision.augment.ipynb.\n",
      "Converted 09b_vision.utils.ipynb.\n",
      "Converted 09c_vision.widgets.ipynb.\n",
      "Converted 10_tutorial.pets.ipynb.\n",
      "Converted 10b_tutorial.albumentations.ipynb.\n",
      "Converted 11_vision.models.xresnet.ipynb.\n",
      "Converted 12_optimizer.ipynb.\n",
      "Converted 13_callback.core.ipynb.\n",
      "Converted 13a_learner.ipynb.\n",
      "Converted 13b_metrics.ipynb.\n",
      "Converted 14_callback.schedule.ipynb.\n",
      "Converted 14a_callback.data.ipynb.\n",
      "Converted 15_callback.hook.ipynb.\n",
      "Converted 15a_vision.models.unet.ipynb.\n",
      "Converted 16_callback.progress.ipynb.\n",
      "Converted 17_callback.tracker.ipynb.\n",
      "Converted 18_callback.fp16.ipynb.\n",
      "Converted 18a_callback.training.ipynb.\n",
      "Converted 18b_callback.preds.ipynb.\n"
     ]
    }
   ],
   "source": [
    "#hide\n",
    "from nbdev.export import *\n",
    "notebook2script()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "jupytext": {
   "split_at_heading": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
